<template>
  <div class="w-full">
    <el-form ref="searchForm" :model="searchParams" :inline="true" :label-width="searchOptions.labelWidth" @submit.native.prevent>
      <el-form-item
        v-for="items in searchOptions.formOptions"
        v-show="!items.hide"
        :key="items.prop"
        :prop="items.prop"
        :label="items.label || ''"
        :label-width="items.labelWidth || searchOptions.labelWidth"
        :rules="items.rules"
      >
        <!-- 普通输入框 -->
        <el-input
          v-if="items.element === 'el-input'"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :maxlength="items.maxlength || 50"
          :clearable="!items.noClearable"
          :placeholder="items.placeholder || '请输入'"
          @keyup.enter.native="onSearch"
        >
          <el-button v-if="items.prependIcon" slot="prepend" :icon="items.prependIcon" />
          <template v-else-if="items.prependText" slot="prepend">{{ items.prependText }}</template>
          <el-button v-if="items.appendIcon" slot="append" :icon="items.appendIcon" />
          <template v-else-if="items.appendText" slot="append">{{ items.appendText }}</template>
        </el-input>

        <!-- 字典类型下拉框 -->
        <el-select
          v-if="items.element === 'el-select-dict'"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :clearable="!items.noClearable"
          :filterable="!items.noFilterable"
          :placeholder="items.placeholder || '请选择'"
          @change="onSearch"
        >
          <el-option v-for="dict in items.options" :key="dict.value" :label="dict.label" :value="dict.value" />
        </el-select>

        <!-- 普通下拉框 -->
        <el-select
          v-if="items.element === 'el-select'"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :clearable="!items.noClearable"
          :filterable="!items.noFilterable"
          :placeholder="items.placeholder || '请选择'"
          @change="onSearch"
        >
          <el-option v-for="item in items.options" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>

        <!-- 日期范围 daterange/datetimerange -->
        <el-date-picker
          v-if="isDatePickerDateRange(items)"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :type="items.type || 'daterange'"
          :start-placeholder="items.startPlaceholder || '开始日期'"
          :range-separator="items.rangeSeparator || '-'"
          :end-placeholder="items.endPlaceholder || '结束日期'"
          :default-time="['00:00:00', '23:59:59']"
          :value-format="items.valueFormat || 'yyyy-MM-dd'"
          @change="onSearch"
        />

        <!-- 月份范围 monthrange -->
        <el-date-picker
          v-if="isDatePickerMonthRange(items)"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          type="monthrange"
          :start-placeholder="items.startPlaceholder || '开始日期'"
          :range-separator="items.rangeSeparator || '-'"
          :end-placeholder="items.endPlaceholder || '结束日期'"
          :value-format="items.valueFormat || 'yyyy-MM'"
          @change="onSearch"
        />

        <!-- 其它时间类型 others -->
        <el-date-picker
          v-if="isDatePickerOthers(items)"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :type="items.type"
          :placeholder="items.placeholder || '请选择日期'"
          :value-format="items.valueFormat || 'yyyy-MM-dd'"
          :picker-options="items.pickerOptions || {}"
          @change="onSearch"
        />

        <!-- 级联选择器 cascader -->
        <el-cascader
          v-if="items.element === 'el-cascader'"
          v-model.trim="searchParams[items.prop]"
          v-bind="bindProps(items)"
          :style="{ width: items.width || handleWidth(items) }"
          :clearable="!items.noClearable"
          :placeholder="items.placeholder || '请选择'"
          :separator="items.separator || '/'"
          :props="items.props || cascaderProps"
          @change="onSearch"
        />
      </el-form-item>

      <slot />

      <!-- 按钮集合 -->
      <el-form-item>
        <el-button
          v-for="items in getBtnItems"
          :key="items.key"
          v-hasPermi="items.permi"
          v-bind="bindProps(items)"
          :loading="items.loading && ['onSearch', 'onReset'].includes(items.key)"
          v-on="items.events"
          @click="btnClick(items)"
        >
          {{ items.label }}
        </el-button>
      </el-form-item>
    </el-form>

    <!-- 文件导入弹窗 -->
    <FileImport ref="fileImport" />
  </div>
</template>

<script>
export default {
  props: {
    isSearch: { type: Boolean, default: true }, // 是否使用默认搜索重置按钮
    searchOptions: { type: Object, required: true, default: () => ({}) }, // 搜索表单配置
    loadDone: { type: Boolean, default: null } // 数据是否请求完成，用于控制按钮状态
  },
  data() {
    return {
      // 级联选择器 props 属性
      cascaderProps: {
        expandTrigger: 'click', // 次级菜单的展开方式
        multiple: false, // 是否多选
        checkStrictly: false, // 父子节点是否不关联
        emitPath: false, // 在选中节点改变时，是否返回由该节点所在的各级菜单的值所组成的数组，若设置 false，则只返回该节点的值
        value: 'value',
        label: 'label',
        children: 'children',
        disabled: 'disabled', // 指定选项的禁用为选项对象的某个属性值
        leaf: 'leaf' // 指定选项的叶子节点的标志位为选项对象的某个属性值
      },
      defaultBtns: [
        {
          label: '搜索',
          permi: ['*:*:*'],
          icon: 'el-icon-search',
          type: 'primary',
          key: 'onSearch',
          loading: false
        },
        {
          label: '重置',
          permi: ['*:*:*'],
          icon: 'el-icon-refresh',
          key: 'onReset',
          loading: false
        }
      ],
      searchParams: {}
    }
  },

  computed: {
    getBtnItems() {
      if (this.isSearch) return this.defaultBtns.concat(this.searchOptions.btnItems || [])
      return this.searchOptions.btnItems
    }
  },

  watch: {
    loadDone(val) {
      if (val && this.loadDone !== null) {
        this.defaultBtns?.forEach(item => {
          item.key === 'onSearch' && (item.loading = false)
          item.key === 'onReset' && (item.loading = false)
        })
      }
    }
  },

  methods: {
    // el-date-picker (type: daterange/datetimerange)
    isDatePickerDateRange(val) {
      const isDatePicker = val.element === 'el-date-picker'
      if (!isDatePicker) return false
      const isDateRange = !val.type || val.type === 'daterange' || val.type === 'datetimerange'
      return isDatePicker && isDateRange
    },

    // el-date-picker (type: monthrange)
    isDatePickerMonthRange(val) {
      const isDatePicker = val.element === 'el-date-picker'
      if (!isDatePicker) return false
      const isMonthRange = val.type === 'monthrange'
      return isDatePicker && isMonthRange
    },

    //  el-date-picker (type: other)
    isDatePickerOthers(val) {
      const isDatePicker = val.element === 'el-date-picker'
      if (!isDatePicker) return false
      return isDatePicker && !this.isDatePickerDateRange(val) && !this.isDatePickerMonthRange(val)
    },

    // 绑定属性
    bindProps(val) {
      const obj = val ? JSON.parse(JSON.stringify(val)) : {}
      // 移除冗余属性
      delete obj.label
      delete obj.prop
      delete obj.element
      delete obj.initValue
      delete obj.rules
      delete obj.events
      if (obj.element === 'el-select') {
        delete obj.options
      }
      return obj
    },

    // 元素宽度
    handleWidth(val) {
      let width = '140px'
      if (val.element === 'el-date-picker') {
        if (!val.type || val.type === 'daterange') return (width = '250px')
        if (val.type === 'datetimerange') return (width = '360px')
        if (val.type === 'monthrange') return (width = '210px')
        if (val.type === 'datetime') return (width = '200px')
      }
      return width
    },

    // 校验
    onValidate(callback) {
      this.$refs['searchForm']?.validate(valid => valid && callback())
    },

    onSearch() {
      if (this.loadDone !== null) {
        this.defaultBtns?.forEach(item => {
          item.key === 'onSearch' && (item.loading = true)
          item.key === 'onReset' && (item.loading = false)
        })
      }
      this.onValidate(() => this.$emit('onSearch', this.searchParams))
    },

    btnClick(val) {
      if (val.key === 'onImport') {
        Object.assign(this.$refs.fileImport?.upload, val.upload)
        this.$emit(val.key)
        return
      }
      if (val.key === 'onExport') {
        this.onValidate(() => this.$emit('onExport', this.searchParams))
        return
      }
      if (val.key === 'onSearch') {
        this.onSearch()
        return
      }
      if (val.key === 'onReset') {
        this.searchParams = {}
        this.resetFields()
        if (this.loadDone !== null) {
          this.defaultBtns?.forEach(item => {
            item.key === 'onSearch' && (item.loading = false)
            item.key === 'onReset' && (item.loading = true)
          })
        }
        this.$emit('onSearch')
        this.$emit('onReset')
        return
      }
      this.$emit(val.key)
    },

    resetFields() {
      this.$refs['searchForm']?.resetFields()
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .el-cascader--mini {
  .el-input--mini {
    .el-input__inner {
      height: 28px !important;
      line-height: 28px !important;
    }
  }
  .el-cascader__tags {
    .el-tag {
      margin-top: 4px !important;
    }
  }
}

::v-deep .el-cascader--small {
  .el-input--small {
    .el-input__inner {
      height: 32px !important;
      line-height: 32px !important;
    }
  }
  .el-cascader__tags {
    .el-tag {
      margin-top: 4px !important;
    }
  }
}
</style>
